package Pownce;

use strict;
use warnings;

=head1 NAME

Pownce - API for pownce.com

=head1 SYNOPSIS

	use Pownce;
	
	my $pownce = Pownce->new(username => 'lee', password => 'aylward');
	$pownce->send_note('public','hi all, i sent this from perl!');

=head1 DESCRIPTION

C<Pownce> is a class for interacting with the pownce.com website.
Currently it can only login and upload notes.

=cut

use LWP::UserAgent;
use XML::XPath;
use Digest::SHA qw/sha1 sha1_hex/;
use MIME::Base64;
use LWP::MediaTypes;
use File::Basename;
use File::Slurp;
use Data::Dumper;
use Carp;
use constant { TRUE => 1, FALSE => 0 };

our $VERSION = '0.01';
our @ISA = qw//;

=head1 METHODS

=cut

my $ua = LWP::UserAgent->new;
my $host = 'http://pownce.com/api/';
my $MIMEBOUNDARY = '------------ae0GI3ei4gL6ae0Ij5Ij5ei4KM7ei4';

=head2 new (username => $username, password => $password)

Create a new Pownce object. Requires username and password.

=cut

sub new {
	my ($class,%options) = @_;
	croak "Pownce: Must provide username and password\n"
		if (! $options{username} or ! $options{password} );
	my $self = {
		username	=> $options{username},
		password	=> $options{password},
	};
	bless($self,$class);
	return $self->login;
}

=head2 login ()

Attempts to authenticate against pownce.com. Stores the token 
provided in the response. This method is automatically called
when you create a Pownce object.

=cut

sub login {
	my $self = shift;
	if (my $res = $self->_send_req('login')) {
		if (my $atom = XML::XPath->new(xml =>$res->content)) {
			$self->{token} = $atom->findvalue('/login/@token')->value;
			return $self;
		}
	}
	return FALSE;
}

=head2 send_note ($to, $body)

Send a note to Pownce. Use the recipient 'public' if
you want it sent to everyone.

=cut

sub send_note {
	my ($self,$to,$body) = @_;
	$self->_send_req('notes', data => { 
		note_to => $to, 
		note_body => $body, 
		note_type => 'note-message' 
	});
}

=head2 get_notes ()

Returns an array of notes.

=cut

sub get_notes {
	my $self = shift;
	if (my $req = $self->_send_req('notes/for/' . $self->{username}) ){
		print Dumper $req->content;
		my $xml = XML::XPath->new(xml => $req->content);
		return $xml->find('/feed/entry');
	}
}

=head2 send_file ($filepath, $to, $body)

Send a file to Pownce. Use the recipient 'public' if
you want it sent to everyone. DOES NOT WORK YET!

=cut

sub send_file {
	my ($self,$path,$to,$body) = @_;
	my $mime;
	if (! -e $path) {
		warn "Pownce: $path does not exist\n";
		return FALSE;
	}
	my $data = {
		note_to => ($to eq 'public' ? 'all' : $to),
		note_type => 'note-file',
		note_body => $body,
		Filename => fileparse($path),
		Upload	=> 'Submit Query'
	};

	for my $key ( keys %$data) {
		$mime .= '--' . $MIMEBOUNDARY . "\015";
		$mime .= "Content-Disposition: form-data; name=\"$key\"\015\015";
		$mime .= $data->{$key};
	}
	$mime .= '--' . $MIMEBOUNDARY . "\015";
	$mime .= "Content-Disposition: form-data; name=\"".$data->{Filename}."\"\015";
	$mime .= "Content-Type: " . guess_media_type($path) . "\015\015";
	$mime .= read_file($path, binmode => ':raw') . "\015";
	$mime .= '--' . $MIMEBOUNDARY . "--\015\015";

	$self->_send_req('notes', mime_data => $mime);
}

sub _send_req {
	my ($self,$path,%options) = @_;
	$options{data}{auth} = $self->_wsse_string if $self->{token};
	my $res = $ua->post($host.$path.'/',
		$options{data}||{},
		$self->_headers($options{mime})
	);
	return $res if $res->is_success;
	warn "Pownce: Failed '$path' request; " . $res->status_line;
	return FALSE;
}

sub _headers {
	my ($self,$mime) = @_;
	my %headers = ('Content-Type' => 'application/x-www-urlencoded');
	$headers{'Authorization'} = 'Basic '.
		encode_base64($self->{username}.':'.$self->{password},q{})
		unless $self->{token};
	if ($mime) {
		$headers{'Content-Type'} = "multipart/form-data; boundary=$MIMEBOUNDARY";
		$headers{'Content-Length'} = length $mime;
	}
	return %headers;
}

sub _wsse_string {
	my $self = shift;
	return sprintf('UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
		$self->{username},$self->_password_digest,$self->_nonce,$self->_timestamp);
}

sub _password_digest {
	my $self = shift;
	return encode_base64(sha1($self->_nonce(TRUE) . $self->_timestamp(TRUE) . $self->{token}),q{});
}

sub _nonce {
	my ($self,$new) = @_;
	$self->{nonce} = sha1_hex(time() . rand()) if $new;
	return $self->{nonce};
}

sub _timestamp {
	my ($self,$new) = @_;
	if ($new) {
		my @time = (localtime(time()))[5,4,3,2,1,0];
		$time[0] += 1900;
		$time[1]++;
		$self->{timestamp} =  sprintf("%04d-%02d-%02dT%02d:%02d:%02dZ",@time);
	}
	return $self->{timestamp};
}

=head1 AUTHOR

Lee Aylward <laylward@gmail.com>

=head1 LICENSE

This library is free software, you can redistribute it and/or modify
it under the same terms as Perl itself.

=cut

1;
